package cn.stylefeng.guns.core.util;


import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class RSAUtil {

    private static final String RSA = "RSA";
    private static final int MAX_ENCRYPT_1024 = 117;
    private static final int MAX_DECRYPT_1024 = 128;

    public static final String PRIVATEKEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIhGw+TeqKAcDqggQkS3Z3hkRU46nvgyzbp5/XA3nDO9ijIAzJyFtd18+mQKRsgmDQFAoZiHqCoX755JXWMSY8ofU5dYGRhxCWxb/PX1CDsN9nZ0TRpFLXvvtlJWV/1tjTg7E4GIYez/Xo+QZ/OeQe2HahsB+ysv5gve5JTRrI/jAgMBAAECgYBvZQEOHZ/TOPwWHEBvMUhIFha86pg1pDmc28j6KMrrVF0ZoKOgsn/F7Do0+l1/j/MDehRdvU4OEoDRb4EB0e90/YK/z4zHwlBrjFCQhVJFmXq4pfx4DoTnrpJMjPZoBlP1DDkbljAZ9a+awDYtdfaLFW/ncNAmf7VGS+vRZODY6QJBANeYP+nFhQd/VSlC1N+HN/toAH0GHb/Okxu20/PACA577Zc6bt2IdZN9WuXOeYY/Z9x3M6D9isD2KzyFsl9KPLcCQQCh0QB56XkHUSrXA3zoSLgf3RgCKGhC/96gyh1u+u4oIuxWEanK4fPoXfdQQPBLXJ6fTGUswu2ppP2I8U6uX/I1AkEAjIE9zgWbH/q9LonOn+rI8kCiaNiOlM11FA+/7FBPL9lWS0OasyfWsIt2rOQ2UOaLsqPA8v+p6P3Fyci8KdwA2wJAa17hMAOpWR+Ui4M2+HJ4KjxsV9I0DHD3aj1ydldue5dgtmOWBJcVXtQq7EeKqpbUceMhJyhYxr5BtQJZMP9dGQJAO2w36vuB9GEcR7A0P1fAdUvqaQhMgOyqGNI5vrzYFWJF0GnVg7uiwHoBF4K3KejbK4dJSZ6tQbZYyNZ2447VVg==";
    public static final String PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIRsPk3qigHA6oIEJEt2d4ZEVOOp74Ms26ef1wN5wzvYoyAMychbXdfPpkCkbIJg0BQKGYh6gqF++eSV1jEmPKH1OXWBkYcQlsW/z19Qg7DfZ2dE0aRS1777ZSVlf9bY04OxOBiGHs/16PkGfznkHth2obAfsrL+YL3uSU0ayP4wIDAQAB";

    private static byte[] decryptBASE64(String src) {
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            return decoder.decodeBuffer(src);
        } catch (Exception ex) {
            return null;
        }

    }
    /**
     * 该base64方法会自动换行
     * @param src
     * @return
     */
    private static String encryptBASE64(byte[] src) {
        BASE64Encoder encoder = new BASE64Encoder();

        return encoder.encode(src);
    }
    /**
     * 公钥分段加密
     * @param data 源数据
     * @param publicKey 公钥(BASE64编码)
     * @param length 段长
     * @return
     * @throws Exception
     */
    private static byte[] encryptByPublicKey(byte[] data, String publicKey,int length)
            throws Exception {
        byte[] keyBytes = decryptBASE64(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > length) {
                cache = cipher.doFinal(data, offSet, length);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * length;
        }
        byte[] encryptData = out.toByteArray();
        out.close();
        return encryptData;
    }

    /** *//**
     * <P>
     * 私钥解密
     * </p>
     *
     * @param data 已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    private static byte[] decryptByPrivateKey(byte[] data, String privateKey,int length)
            throws Exception {
        byte[] keyBytes =  decryptBASE64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > length) {
                cache = cipher.doFinal(data, offSet, length);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * length;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /**
     * 加密
     * @param data
     * @return
     */
    public static String encrypt(String data) throws Exception {
        return encryptBASE64(encryptByPublicKey(data.getBytes(), PUBLICKEY, MAX_ENCRYPT_1024)).replaceAll("[+]", "@");
    }

    /**
     * 解密
     * @param data
     * @return
     */
    public static String decrypt(String data) throws Exception {
        return new String(decryptByPrivateKey(decryptBASE64(data.replaceAll("@", "+")), PRIVATEKEY, MAX_DECRYPT_1024));
    }


    public static void genKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到Map
        System.out.println(publicKeyString);  //0表示公钥
        System.out.println(privateKeyString);  //1表示私钥
    }

    public static void main(String[] args) throws Exception {
        //加密字符串
        String message = "372301199201082911";
        String messageEn = encrypt(message);
        System.out.println(message + "\t加密后的字符串为:" + messageEn);

    }


}
